//Random Game Engine
//Copyright (C) 2013  Nikolay Dionisov

//This program is free software: you can redistribute it and/or modify
//it under the terms of the GNU General Public License as published by
//the Free Software Foundation, either version 3 of the License, or
//(at your option) any later version.

//This program is distributed in the hope that it will be useful,
//but WITHOUT ANY WARRANTY; without even the implied warranty of
//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//GNU General Public License for more details.

//You should have received a copy of the GNU General Public License
//along with this program.  If not, see <http://www.gnu.org/licenses/>.

#include "Sheduler.h"
#include <time.h>
#include <memory>

namespace re
{
	namespace core
	{
		void Sheduler::AddSystem(ISystem* system, int priority)
		{
			SystemState sys;
			sys.system = std::shared_ptr<ISystem>(system);
			sys.priority = priority;
			sys.time = clock();
			sys.task = 0;
			systems_.push_back(sys);
		}
		void Sheduler::RemoveSystems(ManagerContainer* managers)
		{
			SessionId sid = managers->task_manager->StartSession();
			for(int i = 0; i < systems_.size(); ++i)
			{
				managers->task_manager->AddTask(WorkPtr(new ShutDownWork(systems_[i].system.get())), sid);
			}
			managers->task_manager->FinishSession(sid);
			//now wait till the tasks are done
			bool can_go = false;
			while(!can_go)
			{
				_sleep(10);
				can_go = true;
				for(int i = 0; i < systems_.size(); ++i)
				{
					if(!managers->task_manager->IsCompleted(systems_[i].task))
					{
						can_go = false;
						continue;
					}
				}
			}
		}
		void Sheduler::UpdateSystems(ManagerContainer* managers)
		{
			unsigned int time = clock();
			SystemState temp;
			//calculate scores
			for(unsigned int i = 0; i < systems_.size(); ++i)
			{
				systems_[i].score = (float)systems_[i].priority * (float)(time - systems_[i].time);
			}
			//sort by scores
			for(unsigned int i = 0; i < systems_.size() - 1; ++i)
			{
				for(unsigned int u = i; u < systems_.size(); ++u)
				{
					if(systems_[i].score < systems_[u].score)
					{
						temp = systems_[i];
						systems_[i] = systems_[u];
						systems_[u] = temp;
					}
				}
			}
			//loop through all systems and check if they can be pushed in the queue
			for(unsigned int i = 0; i < systems_.size(); ++i)
			{
				if(managers->task_manager->IsCompleted(systems_[i].task))
				{
					SessionId id = managers->task_manager->StartSession();
					UpdateWork* work_todo = new UpdateWork(systems_[i].system.get());
					work_todo->id = managers->task_manager->AddTask(WorkPtr(work_todo), id);
					managers->task_manager->FinishSession(id);
					systems_[i].time = time;
					systems_[i].task = work_todo->id;
				}
			}
		}
	}
}

